﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Widgets;
using System.Windows.Media;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年2月20日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：如果当前选定的是个内容控件，则调用Commands.InsertRelationCommand.InsertRelation()插入一个关系。
    /// 　　　　　如果当前选定的是个ShapeWidget，则向指定方向添加格式类似的ShapeWidget来模拟表格（单元格）。
    ///           ★如果目标位置已存在一个同尺寸的ShapeWidget，则直接选定该ShapeWidget而不会添加。
    /// </summary>
    public static class InsertSimilarWidgetAtCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static InsertSimilarWidgetAtCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "InsertSimilarWidgetAtCommand",
                "InsertSimilarWidgetAtCommand",
                typeof(InsertSimilarWidgetAtCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //PageEditor mainPe = manager.GetMainSelectedPageEditor();
            //if (mainPe == null)
            //{
            //    e.CanExecute = false;
            //    return;
            //}

            //Widget w = mainPe.GetMainSelectedWidget();
            //if ((w is Widgets.RectangleWidget == false) && (w is Widgets.ContentWidget == false))
            //{
            //    e.CanExecute = false;
            //    return;
            //}

            e.CanExecute = true;
            return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //Execute();//此命令不直接调用。
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        /// <param name="directionKey">只接受方向键。如：Key.Up</param>
        public static string Execute(Key directionKey)
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";

            PageEditor mainPe = manager.GetMainSelectedPageEditor();
            if (mainPe == null) return "　　未找到活动页面。";

            Widgets.Widget curSelWidget = mainPe.GetMainSelectedWidget();

            Point newStartPoint;
            Point newEndPoint;

            Widgets.ContentWidget curContentWidget = curSelWidget as Widgets.ContentWidget;
            if (curContentWidget != null)
            {
                Rect srcRect = curContentWidget.RealRect;
                newStartPoint = new Point(srcRect.Left + srcRect.Width / 2, srcRect.Top + srcRect.Height / 2);
                switch (directionKey)
                {
                    case Key.Up:
                        {
                            newEndPoint = new Point(newStartPoint.X, srcRect.Top - 60);
                            break;
                        }
                    case Key.Down:
                        {
                            newEndPoint = new Point(newStartPoint.X, srcRect.Bottom + 60);
                            break;
                        }
                    case Key.Left:
                        {
                            newEndPoint = new Point(srcRect.Left - 60, newStartPoint.Y);
                            break;
                        }
                    default:
                        {
                            newEndPoint = new Point(srcRect.Right + 60, newStartPoint.Y);
                            break;
                        }
                }

                return Commands.InsertRelationCommand.InsertRelation(mainPe, curContentWidget, newStartPoint, newEndPoint);
                //如果是内容控件，则向四方“拖出（用快捷键）”关联节点（即“关系”）。
            }

            return InsertShapeWidgetAt(directionKey, manager, mainPe, curSelWidget);
        }

        private static string InsertShapeWidgetAt(Key directionKey,
            EditorManager manager, PageEditor mainPe, Widget curSelWidget)
        {
            Widgets.ShapeWidget curShape = curSelWidget as Widgets.ShapeWidget;//所有的Shape都支持ICanBeLinked接口。

            if (curShape == null) return "　　没找到活动部件，或当前活动部件不是形状部件。";

            //先判断目标位置有没有其它形状部件（内容部件不会调用这个方法），如果有，直接选定，而不是添加新形状。

            Point newStartPoint;
            Point newEndPoint;

            switch (directionKey)
            {
                case Key.Up:
                    {
                        Rect curRealRect = curShape.RealRect;
                        Rect destRect = new Rect(curRealRect.Left, curRealRect.Top - curRealRect.Height - 10,
                            curRealRect.Width, curRealRect.Height + 10);

                        Widgets.ShapeWidget destShape = null;
                        foreach (UIElement ue in mainPe.Children)
                        {
                            if (ue == curShape) continue;
                            Widgets.ShapeWidget swInLoop = ue as Widgets.ShapeWidget;
                            if (swInLoop == null) continue;

                            Rect swRealRect = swInLoop.RealRect;
                            if (swRealRect.IntersectsWith(destRect) == false) continue;
                            else
                            {
                                if (swRealRect.IntersectsWith(curRealRect)) continue;
                                //虽然与目标区域有交集，但与当前部件也有交集，不选中。

                                destShape = swInLoop; break;
                            }
                        }

                        if (destShape != null)
                        {
                            destShape.SelectOnlySelf();
                            return string.Empty;
                        }

                        //如果目标位置没有，才需要添加新矩形。
                        //新矩形的位置
                        newStartPoint = new Point(destRect.Left, destRect.Top);
                        newEndPoint = new Point(newStartPoint.X + curRealRect.Width,
                            newStartPoint.Y + curRealRect.Height);

                        if (newStartPoint.Y <= 0)
                        {
                            return "　　页面顶部没有足够空间添加另一个形状部件";
                        }

                        break;
                    }
                case Key.Down:
                    {
                        Rect curRealRect = curShape.RealRect;
                        Rect destRect = new Rect(curRealRect.Left, curRealRect.Bottom,
                            curRealRect.Width, curRealRect.Height + 10);

                        Widgets.ShapeWidget destShape = null;
                        foreach (UIElement ue in mainPe.Children)
                        {
                            if (ue == curShape) continue;
                            Widgets.ShapeWidget swInloop = ue as Widgets.ShapeWidget;
                            if (swInloop == null) continue;

                            Rect swRealRect = swInloop.RealRect;
                            if (swRealRect.IntersectsWith(destRect) == false) continue;
                            else
                            {
                                if (swRealRect.IntersectsWith(curRealRect)) continue;
                                //虽然与目标区域有交集，但与当前部件也有交集，不选中。

                                destShape = swInloop; break;
                            }
                        }

                        if (destShape != null)
                        {
                            destShape.SelectOnlySelf();
                            return string.Empty;
                        }

                        //如果目标位置没有，才需要添加新矩形。
                        //新矩形的位置
                        newStartPoint = new Point(curRealRect.Left, curRealRect.Bottom + 10);
                        newEndPoint = new Point(newStartPoint.X + curRealRect.Width,
                            newStartPoint.Y + curRealRect.Height);

                        if (newEndPoint.Y >= mainPe.ActualHeight)
                        {
                            return "　　页面底部没有足够空间添加另一个形状部件";
                        }

                        break;
                    }
                case Key.Left:
                    {
                        Rect curRealRect = curShape.RealRect;
                        Rect destRect = new Rect(curRealRect.Left - 10 - curRealRect.Width,
                            curRealRect.Top, curRealRect.Width + 10, curRealRect.Height);

                        Widgets.ShapeWidget destShape = null;
                        foreach (UIElement ue in mainPe.Children)
                        {
                            if (ue == curShape) continue;
                            Widgets.ShapeWidget swInloop = ue as Widgets.ShapeWidget;
                            if (swInloop == null) continue;

                            Rect swRealRect = swInloop.RealRect;
                            if (swRealRect.IntersectsWith(destRect) == false) continue;
                            else
                            {
                                if (swRealRect.IntersectsWith(curRealRect)) continue;
                                //虽然与目标区域有交集，但与当前部件也有交集，不选中。

                                destShape = swInloop; break;
                            }
                        }

                        if (destShape != null)
                        {
                            destShape.SelectOnlySelf();
                            return string.Empty;
                        }

                        //如果目标位置没有，才需要添加新矩形。
                        //新矩形的位置
                        newStartPoint = new Point(destRect.Left, destRect.Top);
                        newEndPoint = new Point(newStartPoint.X + curRealRect.Width,
                            newStartPoint.Y + curRealRect.Height);

                        if (newStartPoint.X <= 0)
                        {
                            return "　　页面左部没有足够空间添加另一个形状部件副本";
                        }

                        break;
                    }
                case Key.Right:
                    {
                        Rect curRealRect = curShape.RealRect;
                        Rect destRect = new Rect(curRealRect.Right,
                            curRealRect.Top, curRealRect.Width + 10, curRealRect.Height);

                        Widgets.ShapeWidget destShape = null;
                        foreach (UIElement ue in mainPe.Children)
                        {
                            if (ue == curShape) continue;
                            Widgets.ShapeWidget swInloop = ue as Widgets.ShapeWidget;
                            if (swInloop == null) continue;

                            Rect swRealRect = swInloop.RealRect;
                            if (swRealRect.IntersectsWith(destRect) == false) continue;
                            else
                            {
                                if (swRealRect.IntersectsWith(curRealRect)) continue;
                                //虽然与目标区域有交集，但与当前部件也有交集，不选中。

                                destShape = swInloop; break;
                            }
                        }

                        if (destShape != null)
                        {
                            destShape.SelectOnlySelf();
                            return string.Empty;
                        }

                        //如果目标位置没有，才需要添加新矩形。
                        //新矩形的位置
                        newStartPoint = new Point(curRealRect.Right + 10, curRealRect.Top);
                        newEndPoint = new Point(newStartPoint.X + curRealRect.Width,
                            newStartPoint.Y + curRealRect.Height);

                        if (newEndPoint.X >= mainPe.ActualWidth)
                        {
                            return "　　页面右侧没有足够空间添加另一个形状部件副本。";
                        }

                        break;
                    }
                default: return string.Empty;//不考虑其它情况。直接返回。
            }

            XmlNode widgetSetNode = mainPe.WidgetSetNode;
            if (widgetSetNode == null) return "　　未找到WidgetSet节点，无法添加形状部件。";

            XmlNode newNode; Widgets.ShapeWidget sw;

            switch (curSelWidget.GetType().Name)
            {
                case "EllipseWidget":
                    {
                        newNode = widgetSetNode.AppendXmlAsChild(Properties.Resources.EllipseXml);
                        Widgets.EllipseWidget ew;
                        sw = ew = new Widgets.EllipseWidget(mainPe);

                        ew.XmlData = newNode;
                        ew.NewID();

                        ew.StartPoint = newStartPoint;
                        ew.EndPoint = newEndPoint;

                        break;
                    }
                case "RectangleWidget":
                    {
                        Widgets.RectangleWidget curRectangle = curSelWidget as Widgets.RectangleWidget;
                        if (curRectangle == null) return "　　发生意外错误！未能将CurSelWidget转换为RectangleWidget。";

                        newNode = widgetSetNode.AppendXmlAsChild(Properties.Resources.RectangleXml);
                        Widgets.RectangleWidget rw;
                        sw = rw = new Widgets.RectangleWidget(mainPe);

                        rw.XmlData = newNode;
                        rw.NewID();

                        rw.StartPoint = newStartPoint;
                        rw.EndPoint = newEndPoint;
                        rw.FixTextWidth = curRectangle.FixTextWidth;
                        rw.Radius = curRectangle.Radius;

                        break;
                    }
                case "RhombWidget":
                    {
                        newNode = widgetSetNode.AppendXmlAsChild(Properties.Resources.RhombXml);
                        Widgets.RhombWidget rw;
                        sw = rw = new Widgets.RhombWidget(mainPe);

                        rw.XmlData = newNode;
                        rw.NewID();

                        rw.StartPoint = newStartPoint;
                        rw.EndPoint = newEndPoint;

                        Widgets.RhombWidget curRw = curShape as Widgets.RhombWidget;
                        if (curRw != null)
                        {
                            rw.WidgetForm = curRw.WidgetForm;
                        }

                        break;
                    }
                case "TriangleWidget":
                    {
                        newNode = widgetSetNode.AppendXmlAsChild(Properties.Resources.TriangleXml);
                        Widgets.TriangleWidget newTriangle = new Widgets.TriangleWidget(mainPe);
                        newTriangle.XmlData = newNode;
                        newTriangle.NewID();

                        newTriangle.StartPoint = newStartPoint;
                        newTriangle.EndPoint = newEndPoint;

                        Widgets.TriangleWidget curTriangle = curSelWidget as Widgets.TriangleWidget;
                        if (curTriangle == null) return "　　发生意外错误！未能将CurSelWidget转换为TriangleWidget。";

                        Rect curRealRect = curShape.RealRect;
                        //这个比较特殊，得用新矩形的左上角加上原部件三个控制点到原部件左上角的偏移量。
                        newTriangle.StartPoint = new Point(newStartPoint.X + (curTriangle.StartPoint.X - curRealRect.X),
                            newStartPoint.Y + (curTriangle.StartPoint.Y - curRealRect.Y));
                        newTriangle.CenterCPPoint = new Point(newStartPoint.X + (curTriangle.CenterCPPoint.X - curRealRect.X),
                            newStartPoint.Y + (curTriangle.CenterCPPoint.Y - curRealRect.Y));
                        newTriangle.EndPoint = new Point(newStartPoint.X + (curTriangle.EndPoint.X - curRealRect.X),
                            newStartPoint.Y + (curTriangle.EndPoint.Y - curRealRect.Y));

                        sw = newTriangle;
                        break;
                    }
                default: return "　　发生意外！不能识别源部件类型。";
            }

            //sw.StartPoint = newStartPoint; sw.EndPoint = newEndPoint;//Shape不直接支持这两个点。子类才支持。

            //按源部件值设置属性
            if (curShape.IsWidgetPropertySetted(XmlTags.IsShadowVisibleTag)) sw.IsShadowVisible = curShape.IsShadowVisible;
            if (curShape.IsWidgetPropertySetted(XmlTags.WidgetOpacityTag)) sw.WidgetOpacity = curShape.WidgetOpacity;
            if (curShape.IsWidgetPropertySetted(XmlTags.WidgetForeColor)) sw.WidgetForeColor = curShape.WidgetForeColor;
            if (curShape.IsWidgetPropertySetted(XmlTags.WidgetBackColor)) sw.WidgetBackColor = curShape.WidgetBackColor;
            if (curShape.IsWidgetPropertySetted(XmlTags.WidgetLineColorTag)) sw.WidgetLineColor = curShape.WidgetLineColor;
            if (curShape.IsWidgetPropertySetted(XmlTags.WidgetLineWidthTag)) sw.WidgetLineWidth = curShape.WidgetLineWidth;
            if (curShape.IsWidgetPropertySetted(XmlTags.LineDashTag)) sw.LineDash = curShape.LineDash;
            //sw.FixTextWidth = curShape.FixTextWidth;

            //Backcolor是特殊的，需要另作处理，因为支持了自定义图像背景
            var srcWidgetBackColorName = BrushManager.GetName(curShape.WidgetBackColor);
            if (string.IsNullOrWhiteSpace(srcWidgetBackColorName) || srcWidgetBackColorName == typeof(ImageBrush).Name)
            {
                if (string.IsNullOrWhiteSpace(curShape.ImageBase64) == false)
                {
                    sw.ImageBase64 = curShape.ImageBase64;
                }
            }
            else
            {
                if (curShape.IsWidgetPropertySetted(XmlTags.WidgetBackColor))
                {
                    sw.WidgetBackColor = curShape.WidgetBackColor;
                }
            }

            //菱形形态设置被放到前面switch中去了。

            ModifingInfo info = new ModifingInfo() { ModifingDescription = "添加形状部件" };
            manager.GetSelectedPageEditorStatus(info);
            manager.GetSelectedWidgetStatus_Old(info);
            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

            Action actAddShapeWidget = new Action(ActionType.WidgetAdded,
                mainPe.Id, sw.Id, null, sw.XmlData.OuterXml);

            mainPe.AddWidget(sw);

            sw.SelectOnlySelf();

            info.NewMainSelectedWidgetID = sw.Id;
            mi.AddAction(actAddShapeWidget);

            //添加相似连接线
            AddSimilarLinkedLine(curShape as Widgets.Interfaces.ICanBeLinkedWidget,
                mainPe, sw as Widgets.Interfaces.ICanBeLinkedWidget, mi);

            manager.RegisterModifingItem(mi);

            return string.Empty;
        }

        internal static void AddSimilarLinkedLine(Widgets.Interfaces.ICanBeLinkedWidget curCanBeLinkedWidget,
            PageEditor pe, Widgets.Interfaces.ICanBeLinkedWidget newCanBeLinkedWidget,
            ModifingItem<Action, ModifingInfo> mi)
        {
            XmlNode widgetSetNode = pe.WidgetSetNode;
            if (widgetSetNode != null)
            {
                List<Widgets.Interfaces.ILinkableLine> linkedLinesList = curCanBeLinkedWidget.GetLinkedLines();
                if (linkedLinesList.Count > 0)
                {

                    //Shift+K与Shift+Enter行为不同：
                    //Shift+Enter只在“有且仅有一条指向源部件的连接线”时才会添加“相似连接线”。
                    //而Shift+K会添加所有可能存在的连接线。
                    foreach (Widgets.Interfaces.ILinkableLine linkedLine in linkedLinesList)
                    {
                        InsertSimilarWidgetAndEditCommand.AddSimilarLinkedLine(curCanBeLinkedWidget, pe, newCanBeLinkedWidget, mi, widgetSetNode, linkedLine);
                    }
                }
            }
        }

        #endregion
    }
}
